/*
* Copyright 2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
 */

package dev

import (
	"bytes"
	"context"
	"math/big"
	"strings"
	"testing"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	ethcommon "github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"

	"github.com/offchainlabs/arbitrum/packages/arb-evm/arbos"
	"github.com/offchainlabs/arbitrum/packages/arb-evm/arboscontracts"
	"github.com/offchainlabs/arbitrum/packages/arb-evm/message"
	"github.com/offchainlabs/arbitrum/packages/arb-rpc-node/arbostestcontracts"
	"github.com/offchainlabs/arbitrum/packages/arb-rpc-node/web3"
	"github.com/offchainlabs/arbitrum/packages/arb-util/common"
	"github.com/offchainlabs/arbitrum/packages/arb-util/hashing"
	"github.com/offchainlabs/arbitrum/packages/arb-util/protocol"
	"github.com/offchainlabs/arbitrum/packages/arb-util/test"
)

func setupFeeChain(t *testing.T, ctx context.Context) (*Backend, *web3.Server, *web3.EthClient, *bind.TransactOpts, *bind.TransactOpts, message.FeeConfig, protocol.ChainParams, common.Address, func()) {
	skipBelowVersion(t, 25)
	privkey, err := crypto.GenerateKey()
	test.FailIfError(t, err)
	auth := bind.NewKeyedTransactor(privkey)

	privkey2, err := crypto.GenerateKey()
	test.FailIfError(t, err)
	aggAuth := bind.NewKeyedTransactor(privkey2)

	config := protocol.ChainParams{
		GracePeriod:               common.NewTimeBlocksInt(3),
		ArbGasSpeedLimitPerSecond: 1999999999,
	}

	netFeeRecipient := common.RandAddress()
	congestionFeeRecipient := common.RandAddress()
	feeConfigInit := message.FeeConfig{
		SpeedLimitPerSecond:    new(big.Int).SetUint64(config.ArbGasSpeedLimitPerSecond),
		L1GasPerL2Tx:           big.NewInt(3700),
		ArbGasPerL2Tx:          big.NewInt(0),
		L1GasPerL2Calldata:     big.NewInt(1),
		ArbGasPerL2Calldata:    big.NewInt(0),
		L1GasPerStorage:        big.NewInt(2000),
		ArbGasPerStorage:       big.NewInt(0),
		ArbGasDivisor:          big.NewInt(10000),
		NetFeeRecipient:        netFeeRecipient,
		CongestionFeeRecipient: congestionFeeRecipient,
	}

	aggInit := message.DefaultAggConfig{Aggregator: common.NewAddressFromEth(aggAuth.From)}
	backend, _, srv, cancelDevNode := NewTestDevNode(
		t,
		*arbosfile,
		config,
		common.NewAddressFromEth(auth.From),
		[]message.ChainConfigOption{feeConfigInit, aggInit},
		true,
	)

	deposit := message.EthDepositTx{
		L2Message: message.NewSafeL2Message(message.ContractTransaction{
			BasicTx: message.BasicTx{
				MaxGas:      big.NewInt(1000000),
				GasPriceBid: big.NewInt(0),
				DestAddress: common.NewAddressFromEth(auth.From),
				Payment:     new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil),
				Data:        nil,
			},
		}),
	}
	if _, err := backend.AddInboxMessage(ctx, deposit, common.RandAddress()); err != nil {
		t.Fatal(err)
	}

	web3Server := web3.NewServer(srv, web3.DefaultConfig, nil)

	client := web3.NewEthClient(srv, true)

	arbAggregator, err := arboscontracts.NewArbAggregator(arbos.ARB_AGGREGATOR_ADDRESS, client)
	test.FailIfError(t, err)

	feeCollector := common.RandAddress()
	aggAuth.GasLimit = 100000000
	_, feeCollectorErr := arbAggregator.SetFeeCollector(aggAuth, aggAuth.From, feeCollector.ToEthAddress())
	aggAuth.GasLimit = 0
	if arbosVersion >= 5 {
		test.FailIfError(t, feeCollectorErr)
	}

	arbOwner, err := arboscontracts.NewArbOwner(arbos.ARB_OWNER_ADDRESS, client)
	test.FailIfError(t, err)

	auth.GasLimit = 100000000
	_, err = arbOwner.SetFairGasPriceSender(auth, aggInit.Aggregator.ToEthAddress(), true)
	test.FailIfError(t, err)

	otherSender := common.RandAddress()
	_, err = arbOwner.SetFairGasPriceSender(auth, otherSender.ToEthAddress(), true)
	test.FailIfError(t, err)

	if doUpgrade {
		UpgradeTestDevNode(t, ctx, backend, srv, auth)
		enableRewrites(t, backend, srv, auth)
	}

	senders, err := arbOwner.GetAllFairGasPriceSenders(&bind.CallOpts{})
	test.FailIfError(t, err)
	if len(senders) != 64 {
		t.Fatal("unexpected length")
	}
	correctSenders := make([]byte, 64)
	copy(correctSenders[12:], aggInit.Aggregator[:])
	copy(correctSenders[44:], otherSender[:])

	correctSenders2 := make([]byte, 64)
	copy(correctSenders2[12:], otherSender[:])
	copy(correctSenders2[44:], aggInit.Aggregator[:])
	if !bytes.Equal(senders, correctSenders) && !bytes.Equal(senders, correctSenders2) {
		t.Log("senders", hexutil.Encode(senders))
		t.Log("correctSenders", hexutil.Encode(correctSenders))
		t.Error("wrong senders")
	}

	aggIsFair, err := arbOwner.IsFairGasPriceSender(&bind.CallOpts{}, aggInit.Aggregator.ToEthAddress())
	test.FailIfError(t, err)
	if !aggIsFair {
		t.Error("expected fair agg")
	}

	otherIsFair, err := arbOwner.IsFairGasPriceSender(&bind.CallOpts{}, otherSender.ToEthAddress())
	test.FailIfError(t, err)
	if !otherIsFair {
		t.Error("expected fair other")
	}

	randomNotFair, err := arbOwner.IsFairGasPriceSender(&bind.CallOpts{}, common.RandAddress().ToEthAddress())
	test.FailIfError(t, err)
	if randomNotFair {
		t.Error("expected unfair random")
	}

	_, err = arbOwner.SetChainParameter(auth, arbos.FeesEnabledParamId, big.NewInt(1))
	test.FailIfError(t, err)
	auth.GasLimit = 0
	// Reset this, which geth mutates, but changes after fees are enabled
	auth.GasPrice = nil

	if arbosVersion < 22 {
		if _, err := backend.AddInboxMessage(ctx, deposit, common.RandAddress()); err != nil {
			t.Fatal(err)
		}
	}
	return backend, web3Server, client, auth, aggAuth, feeConfigInit, config, feeCollector, cancelDevNode
}

func TestFees(t *testing.T) {
	ctx := context.Background()
	skipBelowVersion(t, 3)
	backend, _, client, _, aggAuth, feeConfig, config, feeCollector, cancel := setupFeeChain(t, ctx)
	defer cancel()

	agg := common.NewAddressFromEth(aggAuth.From)

	arbGasInfo, err := arboscontracts.NewArbGasInfo(arbos.ARB_GAS_INFO_ADDRESS, client)
	test.FailIfError(t, err)

	arbOwner, err := arboscontracts.NewArbOwner(arbos.ARB_OWNER_ADDRESS, client)
	test.FailIfError(t, err)

	arbAggregator, err := arboscontracts.NewArbAggregator(arbos.ARB_AGGREGATOR_ADDRESS, client)
	test.FailIfError(t, err)

	totalPaid := big.NewInt(0)

	checkPaid := func() {
		t.Helper()
		netFeeBal, err := client.BalanceAt(context.Background(), feeConfig.NetFeeRecipient.ToEthAddress(), nil)
		test.FailIfError(t, err)

		aggBal, err := client.BalanceAt(context.Background(), agg.ToEthAddress(), nil)
		test.FailIfError(t, err)

		feeCollectorBal, err := client.BalanceAt(context.Background(), feeCollector.ToEthAddress(), nil)
		test.FailIfError(t, err)

		totalReceived := new(big.Int).Add(netFeeBal, aggBal)
		totalReceived = totalReceived.Add(totalReceived, feeCollectorBal)
		if totalReceived.Cmp(totalPaid) != 0 {
			t.Error("amount paid different than amount received", totalReceived, totalPaid)
		}

		if arbosVersion <= 4 {
			if aggBal.Cmp(big.NewInt(0)) <= 0 {
				t.Error("currentAggregator should have nonzero balance")
			}
			if feeCollectorBal.Cmp(big.NewInt(0)) != 0 {
				t.Error("fee collector should have 0 balance")
			}
		} else {
			if aggBal.Cmp(big.NewInt(0)) != 0 {
				t.Error("currentAggregator should have 0 balance")
			}
			if feeCollectorBal.Cmp(big.NewInt(0)) <= 0 {
				t.Error("fee collector should have nonzero balance")
			}
		}
		t.Log("Paid", totalPaid)
		t.Log("Net bal", netFeeBal)
		t.Log("Agg bal", aggBal)
		t.Log("Fee col bal", feeCollectorBal)
	}

	userOpts, userAddr := OptsAddressPair(t, nil)
	addSomeBalance(t, ctx, userAddr, backend, client)

	for i := 0; i < 5; i++ {
		t.Log("tx", i)
		tx, err := arbAggregator.SetFeeCollector(userOpts, userOpts.From, userOpts.From)
		test.FailIfError(t, err)
		paid := checkFees(t, backend, tx)
		totalPaid = totalPaid.Add(totalPaid, paid)
		checkPaid()
	}

	networkDest, err := arbOwner.GetChainParameter(&bind.CallOpts{}, arbos.NetworkFeeRecipientParamId)
	test.FailIfError(t, err)
	if ethcommon.BigToAddress(networkDest) != feeConfig.NetFeeRecipient.ToEthAddress() {
		t.Error("wrong network dest", networkDest)
	}
	congestionDest, err := arbOwner.GetChainParameter(&bind.CallOpts{}, arbos.CongestionFeeRecipientParamId)
	test.FailIfError(t, err)
	if ethcommon.BigToAddress(congestionDest) != feeConfig.CongestionFeeRecipient.ToEthAddress() {
		t.Error("wrong congestion dest", congestionDest)
	}

	speedLimitPerSecond, gasPoolMax, maxTxGasLimit, err := arbGasInfo.GetGasAccountingParams(&bind.CallOpts{})
	test.FailIfError(t, err)
	if speedLimitPerSecond.Cmp(new(big.Int).SetUint64(config.ArbGasSpeedLimitPerSecond)) != 0 {
		t.Error("wrong speed limit")
	}
	t.Log("gasPoolMax", gasPoolMax)
	t.Log("maxTxGasLimit", maxTxGasLimit)

	perL2TxWei, perL1CalldataByteWei, perStorageWei, perArgGasBaseWei, perArbGasCongestionWei, perArbGasTotalWei, err := arbGasInfo.GetPricesInWei(&bind.CallOpts{})
	test.FailIfError(t, err)
	t.Log("perL2TxWei", perL2TxWei)
	t.Log("perL1CalldataByteWei", perL1CalldataByteWei)
	t.Log("perStorageWei", perStorageWei)
	t.Log("perArgGasBaseWei", perArgGasBaseWei)
	t.Log("perArbGasCongestionWei", perArbGasCongestionWei)
	t.Log("perArbGasTotalWei", perArbGasTotalWei)

	perL2Tx, perL1CalldataByte, perStorage, err := arbGasInfo.GetPricesInArbGas(&bind.CallOpts{})
	test.FailIfError(t, err)
	t.Log("perL2Tx", perL2Tx)
	t.Log("perL1CalldataByte", perL1CalldataByte)
	t.Log("perStorage", perStorage)

	_, tx, _, err := arbostestcontracts.DeploySimple(userOpts, client)
	test.FailIfError(t, err)

	paid := checkFees(t, backend, tx)
	totalPaid = totalPaid.Add(totalPaid, paid)
	checkPaid()
}

func checkFees(t *testing.T, backend *Backend, tx *types.Transaction) *big.Int {
	t.Helper()
	arbRes, _, _, err := backend.db.GetRequest(common.NewHashFromEth(tx.Hash()))
	test.FailIfError(t, err)
	t.Log("Gas used:", arbRes.CalcGasUsed().Uint64())
	used := new(big.Rat).SetFrac(arbRes.CalcGasUsed(), new(big.Int).SetUint64(tx.Gas()))
	t.Log("percentage", used.FloatString(2))
	if used.Cmp(big.NewRat(85, 100)) < 0 {
		t.Error("too much extra gas estimated")
	}
	return arbRes.FeeStats.Paid.Total()
}

func TestNonAggregatorFee(t *testing.T) {
	ctx := context.Background()
	skipBelowVersion(t, 3)
	backend, web3SServer, client, auth, _, _, _, _, cancel := setupFeeChain(t, ctx)
	defer cancel()

	simpleAddr, _, simple, err := arbostestcontracts.DeploySimple(auth, client)
	test.FailIfError(t, err)
	backend.currentAggregator = common.RandAddress()

	simpleABI, err := abi.JSON(strings.NewReader(arbostestcontracts.SimpleABI))
	test.FailIfError(t, err)
	data := simpleABI.Methods["arrayPush"].ID
	emptyAgg := ethcommon.Address{}

	userOpts, userAddr := OptsAddressPair(t, nil)
	addSomeBalance(t, ctx, userAddr, backend, client)

	for i := 0; i < 4; i++ {
		estimatedGas, err := web3SServer.EstimateGas(ctx, web3.CallTxArgs{
			From:       &userOpts.From,
			To:         &simpleAddr,
			Data:       (*hexutil.Bytes)(&data),
			Aggregator: &emptyAgg,
		}, nil)
		test.FailIfError(t, err)
		userOpts.GasLimit = uint64(estimatedGas)
		t.Log("estimate:", userOpts.GasLimit)
		tx, err := simple.ArrayPush(userOpts)
		test.FailIfError(t, err)
		checkFees(t, backend, tx)
	}
}

func TestRetryableFee(t *testing.T) {
	skipBelowVersion(t, 3)
	ctx := context.Background()
	backend, _, client, auth, _, _, _, _, cancel := setupFeeChain(t, ctx)
	defer cancel()
	nodeInterface, err := arboscontracts.NewNodeInterface(arbos.ARB_NODE_INTERFACE_ADDRESS, client)
	test.FailIfError(t, err)
	simpleABI, err := abi.JSON(strings.NewReader(arbostestcontracts.SimpleABI))
	test.FailIfError(t, err)
	dest, _, _, err := arbostestcontracts.DeploySimple(auth, client)
	test.FailIfError(t, err)

	retryableTx := message.RetryableTx{
		Destination:       common.NewAddressFromEth(dest),
		Value:             big.NewInt(20),
		Deposit:           new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil),
		MaxSubmissionCost: new(big.Int).Exp(big.NewInt(10), big.NewInt(17), nil),
		CreditBack:        common.RandAddress(),
		Beneficiary:       common.RandAddress(),
		MaxGas:            big.NewInt(0),
		GasPriceBid:       big.NewInt(0),
		Data:              simpleABI.Methods["exists"].ID,
	}

	sender := common.RandAddress()
	gasUsedEstimate, gasPriceEstimate, err := nodeInterface.EstimateRetryableTicket(
		&bind.CallOpts{},
		sender.ToEthAddress(),
		retryableTx.Deposit,
		retryableTx.Destination.ToEthAddress(),
		retryableTx.Value,
		retryableTx.MaxSubmissionCost,
		retryableTx.CreditBack.ToEthAddress(),
		retryableTx.Beneficiary.ToEthAddress(),
		big.NewInt(0),
		big.NewInt(0),
		retryableTx.Data,
	)
	test.FailIfError(t, err)

	retryableTx.MaxGas = big.NewInt(1000000000)
	retryableTx.GasPriceBid = big.NewInt(10000000000)
	requestId, err := backend.AddInboxMessage(ctx, retryableTx, sender)
	test.FailIfError(t, err)

	redeemId := hashing.SoliditySHA3(hashing.Bytes32(requestId), hashing.Uint256(big.NewInt(1)))
	res, _, _, err := backend.db.GetRequest(redeemId)
	test.FailIfError(t, err)

	if web3.ApplyGasPriceBidFactor(res.GasPrice).Cmp(gasPriceEstimate) != 0 {
		t.Error("wrong gas price")
	}

	if res.CalcGasUsed().Cmp(gasUsedEstimate) >= 0 {
		t.Error("more gas used than estimate")
	} else if new(big.Rat).SetFrac(res.CalcGasUsed(), gasUsedEstimate).Cmp(big.NewRat(9, 10)) < 0 {
		t.Error("too much less gas used than estimate")
	}
}

func TestDeposit(t *testing.T) {
	skipBelowVersion(t, 3)
	ctx := context.Background()
	backend, _, client, _, _, _, _, _, cancel := setupFeeChain(t, ctx)
	defer cancel()

	tx := message.EthDepositTx{
		L2Message: message.NewSafeL2Message(message.ContractTransaction{
			BasicTx: message.BasicTx{
				MaxGas:      big.NewInt(5000),
				GasPriceBid: big.NewInt(0),
				DestAddress: common.RandAddress(),
				Payment:     big.NewInt(0),
				Data:        nil,
			},
		}),
	}
	txHash, err := backend.AddInboxMessage(ctx, tx, common.RandAddress())
	test.FailIfError(t, err)

	receipt, err := client.TransactionReceipt(context.Background(), txHash.ToEthHash())
	test.FailIfError(t, err)

	if receipt == nil {
		t.Fatal("expected receipt")
	}
	block, err := client.BlockByHash(context.Background(), receipt.BlockHash)
	test.FailIfError(t, err)
	if len(block.Transactions()) != 1 {
		t.Fatal("expected 1 tx in block")
	}

	arbRes, _, _, err := backend.db.GetRequest(txHash)
	test.FailIfError(t, err)

	t.Log("arbRes", arbRes.IncomingRequest.Kind)
}

const conData = "0x61520456600436101561000d57613e0a565b600035601c52600051341561002157600080fd5b639317c200811415610037573361022052610068565b6380bde2b98114156100635760c43560a01c1561005357600080fd5b602060c461022037600050610068565b6106d4565b60043560a01c1561007857600080fd5b60243560a01c1561008857600080fd5b60443560a01c1561009857600080fd5b60643560a01c156100a857600080fd5b60606084356004016101403760406084356004013511156100c857600080fd5b604060a4356004016101c037602060a4356004013511156100e857600080fd5b601254156100f557600080fd5b600435600655600061028052610280805160208201209050610140805160208201209050141561023c576000606061032060046395d89b416102c0526102dc6004355afa61014257600080fd5b603f3d1161014f57600080fd5b60156103206103205101511061016457600080fd5b6000506103406014806020846103e001018260208501600060045af15050805182019150506007610380527f20795661756c74000000000000000000000000000000000000000000000000006103a0526103806007806020846103e001018260208501600060045af1505080518201915050806103e0526103e0905080600060c052602060c020602082510161012060006002818352015b8261012051602002111561020f57610231565b61012051602002850151610120518501555b81516001018083528114156101fc575b505050505050610297565b61014080600060c052602060c020602082510161012060006003818352015b8261012051602002111561026e57610290565b61012051602002850151610120518501555b815160010180835281141561025b575b5050505050505b6000610280526102808051602082012090506101c080516020820120905014156103d857600060026102c0527f79760000000000000000000000000000000000000000000000000000000000006102e0526102c06002806020846103e001018260208501600060045af1505080518201915050606061038060046395d89b416103205261033c6004355afa61032b57600080fd5b603f3d1161033857600080fd5b60156103806103805101511061034d57600080fd5b6000506103a06014806020846103e001018260208501600060045af1505080518201915050806103e0526103e0905080600160c052602060c020602082510161012060006002818352015b826101205160200211156103ab576103cd565b61012051602002850151610120518501555b8151600101808352811415610398575b505050505050610433565b6101c080600160c052602060c020602082510161012060006002818352015b8261012051602002111561040a5761042c565b61012051602002850151610120518501555b81516001018083528114156103f7575b5050505050505b60206102c0600463313ce5676102605261027c6004355afa61045457600080fd5b601f3d1161046157600080fd5b6000506102c0516102405261024051600255610100610240511061048457600080fd5b602435600755602435610260527f8d55d160c0009eb3d739442df0a3ca089ed64378bfac017e7ddad463f9815b876020610260a1606435600855606435610260527fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef4386020610260a1604435601555604435610260527fdf3c41a916aecbf42361a147f8348c242662c3ce20ecef30e826b80642477a3d6020610260a16102205160095561022051610260527f837b9ad138a0a1839a9637afce5306a5c13e23eb63365686843a5319a243609c6020610260a16103e86017556103e86102605261026051610280527f0810a1c261ca2c0cd86a0152c51c43ba9dc329639d2349f98140891b2ea798eb6020610280a160c860165560c86102605261026051610280527f7a7883b0074f96e2c7fab65eb25abf624c488761a5db889e3bb84855dcc6daaf6020610280a142601155426012556529d635a8e00060145560007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082610640010152602081019050600b610520527f596561726e205661756c740000000000000000000000000000000000000000006105405261052080516020820120905060208261064001015260208101905060056105e0527f302e342e30000000000000000000000000000000000000000000000000000000610600526105e0805160208201209050602082610640010152602081019050466020826106400101526020810190503060208261064001015260208101905080610640526106409050805160208201209050601955005b6325829410811415610769576005610140527f302e342e30000000000000000000000000000000000000000000000000000000610160526101408051602001806101e08284600060045af161072857600080fd5b50506101e0518061020001818260206001820306601f820103905003368237505060206101c05260406101e0510160206001820306601f82010390506101c0f35b63c47f00278114156107ff57604a60043560040161014037602a60043560040135111561079557600080fd5b60075433146107a357600080fd5b61014080600060c052602060c020602082510161012060006003818352015b826101205160200211156107d5576107f7565b61012051602002850151610120518501555b81516001018083528114156107c2575b505050505050005b63b84c824681141561089557603460043560040161014037601460043560040135111561082b57600080fd5b600754331461083957600080fd5b61014080600160c052602060c020602082510161012060006002818352015b8261012051602002111561086b5761088d565b61012051602002850151610120518501555b8151600101808352811415610858575b505050505050005b63ab033ea98114156108c75760043560a01c156108b157600080fd5b60075433146108bf57600080fd5b600435600a55005b63238efcbc81141561091357600a5433146108e157600080fd5b3360075533610140527f8d55d160c0009eb3d739442df0a3ca089ed64378bfac017e7ddad463f9815b876020610140a1005b63d4a22bde8114156109735760043560a01c1561092f57600080fd5b600754331461093d57600080fd5b600435600855600435610140527fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef4386020610140a1005b63ec38a862811415610a325760043560a01c1561098f57600080fd5b600754331461099d57600080fd5b306101605260006101805260006101405261014061012060006002818352015b61012051602002610160015160043514156109db57600183526109eb565b81516001018083528114156109bd575b50505061014051156109fc57600080fd5b600435601555600435610140527fdf3c41a916aecbf42361a147f8348c242662c3ce20ecef30e826b80642477a3d6020610140a1005b637a550365811415610a6b576007543314610a4c57600080fd5b670de0b6b3a76400006004351115610a6357600080fd5b600435601455005b63bdc8144b811415610abb576007543314610a8557600080fd5b600435600e55600435610140527fae565aab888bca5e19e25a13db7b0c9144305bf55cb0f3f4d724f730e5acdd626020610140a1005b6370897b23811415610b1c576007543314610ad557600080fd5b6113886004351115610ae657600080fd5b600435601755600435610140527f0810a1c261ca2c0cd86a0152c51c43ba9dc329639d2349f98140891b2ea798eb6020610140a1005b63fe56e232811415610b7d576007543314610b3657600080fd5b6127106004351115610b4757600080fd5b600435601655600435610140527f7a7883b0074f96e2c7fab65eb25abf624c488761a5db889e3bb84855dcc6daaf6020610140a1005b638a0dac4a811415610c2e5760043560a01c15610b9957600080fd5b600954610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610bd85760018352610be8565b8151600101808352811415610bbc575b50505061014051610bf857600080fd5b600435600955600435610140527f837b9ad138a0a1839a9637afce5306a5c13e23eb63365686843a5319a243609c6020610140a1005b6314c64402811415610cfa5760043560011c15610c4a57600080fd5b60043515610cb657600954610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610c915760018352610ca1565b8151600101808352811415610c75575b50505061014051610cb157600080fd5b610cc4565b6007543314610cc457600080fd5b600435600d55600435610140527fba40372a3a724dca3c57156128ef1e896724b65b37a17f190b1ad5de68f3a4f36020610140a1005b6394148415811415611080576000610120525b610120516004013560a01c15610d2257600080fd5b6020610120510161012052610280610120511015610d3f57610d0d565b600854610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415610d7e5760018352610d8e565b8151600101808352811415610d62575b50505061014051610d9e57600080fd5b61028036610140376103c060006014818352015b6103c05160148110610dc357600080fd5b600c60c052602060c02001546101406103c05160148110610de357600080fd5b602002015260046103c05160148110610dfb57600080fd5b60200201351515610e2e576101406103c05160148110610e1a57600080fd5b602002015115610e2957600080fd5b610fbc565b60006101406103c05160148110610e4457600080fd5b602002015118610e5357600080fd5b60006001600b60046103c05160148110610e6c57600080fd5b602002013560e05260c052604060c02060c052602060c020015411610e9057600080fd5b60006103e05261040060006014818352015b60046104005160148110610eb557600080fd5b60200201351515610ecb5760016103e052610f67565b6101406104005160148110610edf57600080fd5b602002015160046103c05160148110610ef757600080fd5b60200201351415610f095760016103e0525b6103c05161040051131515610f1d57610f57565b60046104005160148110610f3057600080fd5b602002013560046103c05160148110610f4857600080fd5b602002013518610f5757600080fd5b8151600101808352811415610ea2575b50506103e051610f7657600080fd5b60046103c05160148110610f8957600080fd5b60200201356103c05160148110610f9f57600080fd5b600c60c052602060c02001555b8151600101808352811415610db2575b50506004356103c0526024356103e05260443561040052606435610420526084356104405260a4356104605260c4356104805260e4356104a052610104356104c052610124356104e0526101443561050052610164356105205261018435610540526101a435610560526101c435610580526101e4356105a052610204356105c052610224356105e052610244356106005261026435610620527f695ac3ac73f08f2002284ffe563cefe798ee2878a5e04219522e2e99eb89d1686102806103c0a1005b63a9059cbb8114156110d25760043560a01c1561109c57600080fd5b336101405260043561016052602435610180526101805161016051610140516006580161415b565b600050600160005260206000f35b6323b872dd8114156112075760043560a01c156110ee57600080fd5b60243560a01c156110fe57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600460043560e05260c052604060c0203360e05260c052604060c0205410156111cf57600460043560e05260c052604060c0203360e05260c052604060c020546044358082101561116f57600080fd5b808203905090506101405261014051600460043560e05260c052604060c0203360e05260c052604060c020556101405161016052336004357f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610160a35b6004356101405260243561016052604435610180526101805161016051610140516006580161415b565b600050600160005260206000f35b63095ea7b38114156112805760043560a01c1561122357600080fd5b60243560043360e05260c052604060c02060043560e05260c052604060c0205560243561014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b633950935181141561132d5760043560a01c1561129c57600080fd5b60043360e05260c052604060c02060043560e05260c052604060c02080546024358181830110156112cc57600080fd5b8082019050905081555060043360e05260c052604060c02060043560e05260c052604060c0205461014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b63a457c2d78114156113d85760043560a01c1561134957600080fd5b60043360e05260c052604060c02060043560e05260c052604060c02080546024358082101561137757600080fd5b8082039050905081555060043360e05260c052604060c02060043560e05260c052604060c0205461014052600435337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610140a3600160005260206000f35b639fd5a6cf8114156117d55760043560a01c156113f457600080fd5b60243560a01c1561140457600080fd5b606160843560040161014037604160843560040135111561142457600080fd5b60006004351861143357600080fd5b606435151561144357600161144a565b4260643510155b61145357600080fd5b601860043560e05260c052604060c020546101e05260006002610520527f19010000000000000000000000000000000000000000000000000000000000006105405261052060028060208461078001018260208501600060045af150508051820191505060195460208261078001015260208101905060007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c96020826106800101526020810190506004356020826106800101526020810190506024356020826106800101526020810190506044356020826106800101526020810190506101e0516020826106800101526020810190506064356020826106800101526020810190508061068052610680905080516020820120905060208261078001015260208101905080610780526107809050805160208201209050610200526000602060208206610300016101405182840111156115ad57600080fd5b6041806103208260206020880688030161014001600060045af15050818152809050905090508060200151600082518060209013156115eb57600080fd5b80919012156115f957600080fd5b806020036101000a82049050905090506102205260206020602082066103200161014051828401111561162b57600080fd5b6041806103408260206020880688030161014001600060045af150508181528090509050905080602001516000825180602090131561166957600080fd5b809190121561167757600080fd5b806020036101000a8204905090509050610240526040600160208206610340016101405182840111156116a957600080fd5b6041806103608260206020880688030161014001600060045af15050818152809050905090508060200151600082518060209013156116e757600080fd5b80919012156116f557600080fd5b806020036101000a8204905090509050610260526004356102005161028052610260516102a052610220516102c052610240516102e052602060c0608061028060015afa5060c0511461174757600080fd5b604435600460043560e05260c052604060c02060243560e05260c052604060c020556101e051600181818301101561177e57600080fd5b80820190509050601860043560e05260c052604060c02055604435610280526024356004357f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020610280a3600160005260206000f35b6301e1d1148114156117fb5760065801614266565b610140526101405160005260206000f35b63d0e30db0811415611836577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610140523361016052611890565b63b6b55f258114156118575733610160526020600461014037600050611890565b636e553f6581141561188b57602060046101403760243560a01c1561187b57600080fd5b6020602461016037600050611890565b611aee565b601a541561189d57600080fd5b6001601a55600d54156118af57600080fd5b306101a05260006101c05260006101805261018061012060006002818352015b610120516020026101a001516101605114156118ee57600183526118fe565b81516001018083528114156118cf575b505050610180511561190f57600080fd5b61014051610180527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101805114156119d957600e5461014051610160516101805160065801614266565b6101a0526101805261016052610140526101a0518082101561197b57600080fd5b80820390509050602061024060246370a082316101c052336101e0526101dc6006545afa6119a857600080fd5b601f3d116119b557600080fd5b60005061024051808211156119ca57806119cc565b815b9050905061018052611a2a565b600e5461014051610160516101805160065801614266565b6101a0526101805261016052610140526101a05161018051818183011015611a1857600080fd5b808201905090501115611a2a57600080fd5b60006101805111611a3a57600080fd5b6101405161016051610180516101a051610160516101c052610180516101e0526101e0516101c051600658016142c9565b610240526101a052610180526101605261014052610240516101a0526101405161016051610180516101a0516006546101c052336101e0523061020052610180516102205261022051610200516101e0516101c05160065801613faa565b6101a0526101805261016052610140526000506101a0516000526000601a5560206000f35b6375de2902811415611c4c5760206101e060246370a0823161016052306101805261017c6006545afa611b2057600080fd5b601f3d11611b2d57600080fd5b6000506101e051610200526101405161016051610180516101a0516101c0516101e051610200516102005161022052610220516006580161455f565b61028052610200526101e0526101c0526101a052610180526101605261014052610280516101405261018060006014818352015b61018051600c60c052602060c020015461016052610160511515611bc057611c3d565b61014080516101405161016051610180516006600b6101605160e05260c052604060c02060c052602060c02001546101a0526101a0516006580161455f565b6102005261018052610160526101405261020051818183011015611c2257600080fd5b808201905090508152505b8151600101808352811415611b9d575b50506101405160005260206000f35b633ccfd60b811415611c8d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610140523361016052600161018052611d2e565b632e1a7d4d811415611cb45733610160526001610180526020600461014037600050611d2e565b62f714ce811415611ced57600161018052602060046101403760243560a01c15611cdd57600080fd5b6020602461016037600050611d2e565b63e63697c8811415611d2957602060046101403760243560a01c15611d1157600080fd5b60206024610160376020604461018037600050611d2e565b612343565b601a5415611d3b57600080fd5b6001601a55610140516101a052612710610180511115611d5a57600080fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101a0511415611d995760033360e05260c052604060c020546101a0525b60033360e05260c052604060c020546101a0511115611db757600080fd5b60006101a05111611dc757600080fd5b6101405161016051610180516101a0516101c0516101a0516101e0526101e05160065801614413565b610240526101c0526101a052610180526101605261014052610240516101c05260006101e052602061028060246370a0823161020052306102205261021c6006545afa611e3c57600080fd5b601f3d11611e4957600080fd5b600050610280516101c0511115612200576102c060006014818352015b6102c051600c60c052602060c02001546102a0526102a0511515611e895761210e565b602061038060246370a0823161030052306103205261031c6006545afa611eaf57600080fd5b601f3d11611ebc57600080fd5b600050610380516102e0526102e0516101c051111515611edb5761210e565b6101c0516102e05180821015611ef057600080fd5b8082039050905061030052610300516006600b6102a05160e05260c052604060c02060c052602060c020015480821115611f2a5780611f2c565b815b9050905061030052610300511515611f43576120fe565b60206103c06024632e1a7d4d61034052610300516103605261035c60006102a0515af1611f6f57600080fd5b601f3d11611f7c57600080fd5b6000506103c0516103205260206103e060246370a0823161036052306103805261037c6006545afa611fad57600080fd5b601f3d11611fba57600080fd5b6000506103e0516102e05180821015611fd257600080fd5b808203905090506103405260006103205111156120a5576101c080516103205180821015611fff57600080fd5b808203905090508152506101e080516103205181818301101561202157600080fd5b80820190509050815250610140610360525b6103605151602061036051016103605261036061036051101561205557612033565b6102a05161038052610320516103a0526103a051610380516006580161460c565b610340610360525b61036051526020610360510361036052610140610360511015156120a15761207e565b6000505b6006600b6102a05160e05260c052604060c02060c052602060c02001805461034051808210156120d457600080fd5b808203905090508155506010805461034051808210156120f357600080fd5b808203905090508155505b8151600101808352811415611e66575b5050602061034060246370a082316102c052306102e0526102dc6006545afa61213657600080fd5b601f3d1161214357600080fd5b600050610340516102a0526102a0516101c0511115612200576102a0516101c0526101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516101c0516101e0518181830110156121ab57600080fd5b808201905090506102c0526102c0516006580161455f565b610320526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610180526101605261014052610320516101a0525b610180516101c0516101e05181818301101561221b57600080fd5b80820190509050808202821582848304141761223657600080fd5b80905090509050612710808204905090506101e051111561225657600080fd5b600580546101a0518082101561226b57600080fd5b8082039050905081555060033360e05260c052604060c02080546101a0518082101561229657600080fd5b808203905090508155506101a051610200526000337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020610200a36101405161016051610180516101a0516101c0516101e0516006546102005261016051610220526101c0516102405261024051610220516102005160065801613e10565b6101e0526101c0526101a0526101805261016052610140526000506101c0516000526000601a5560206000f35b6399530b0681141561238657604e6002541061235e57600080fd5b600254600a0a610140526101405160065801614413565b6101a0526101a05160005260206000f35b6314b4e26e8114156125b45760043560a01c156123a257600080fd5b6013600c60c052602060c0200154156123ba57600080fd5b600d54156123c757600080fd5b60075433146123d557600080fd5b6000600435186123e457600080fd5b6001600b60043560e05260c052604060c02060c052602060c02001541561240a57600080fd5b60206101a0600463fbfa77cf6101405261015c6004355afa61242b57600080fd5b601f3d1161243857600080fd5b6000506101a051301461244a57600080fd5b60206101a06004631f1fcd516101405261015c6004355afa61246b57600080fd5b601f3d1161247857600080fd5b6000506101a0516006541461248c57600080fd5b612710600f546024358181830110156124a457600080fd5b8082019050905011156124b657600080fd5b60643560443511156124c757600080fd5b61138860843511156124d857600080fd5b600b60043560e05260c052604060c02060c052602060c0206084358155426001820155602435600282015560443560038201556064356004820155426005820155600060068201556000600782015560006008820155506024356101405260443561016052606435610180526084356101a0526004357f5a6abd2af9fe6c0554fa08649e2d86e4393ff19dc304d072d38d295c9291d4dc6080610140a2600f805460243581818301101561258b57600080fd5b808201905090508155506004356013600c60c052602060c0200155600658016147ba565b600050005b637c6a4f248114156127115760043560a01c156125d057600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b61012051602002610160015133141561260f576001835261261f565b81516001018083528114156125f3575b5050506101405161262f57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c02001541161265757600080fd5b600f80546002600b60043560e05260c052604060c02060c052602060c02001548082101561268457600080fd5b808203905090508155506024356002600b60043560e05260c052604060c02060c052602060c0200155600f80546024358181830110156126c357600080fd5b80820190509050815550612710600f5411156126de57600080fd5b602435610140526004357fbda9398315c83ccef012bcaa318a2ff7b680f36429d36597bd4bc25ac11ead596020610140a2005b63e722befe8114156128305760043560a01c1561272d57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b61012051602002610160015133141561276c576001835261277c565b8151600101808352811415612750575b5050506101405161278c57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c0200154116127b457600080fd5b6024356004600b60043560e05260c052604060c02060c052602060c020015410156127de57600080fd5b6024356003600b60043560e05260c052604060c02060c052602060c0200155602435610140526004357f0b728ad785976532c4aaadde09b1cba5f262a7090e83c62d2377bc405678b29c6020610140a2005b634757a15681141561294f5760043560a01c1561284c57600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b61012051602002610160015133141561288b576001835261289b565b815160010180835281141561286f575b505050610140516128ab57600080fd5b60006001600b60043560e05260c052604060c02060c052602060c0200154116128d357600080fd5b6024356003600b60043560e05260c052604060c02060c052602060c020015411156128fd57600080fd5b6024356004600b60043560e05260c052604060c02060c052602060c0200155602435610140526004357f1796a8e0760e2de5b72e7bf64fccb7666c48ceab94cb6cae7cb7eff4b6f641ab6020610140a2005b63d0194ed6811415612a185760043560a01c1561296b57600080fd5b600754331461297957600080fd5b6127106017548082101561298c57600080fd5b8082039050905060243511156129a157600080fd5b60006001600b60043560e05260c052604060c02060c052602060c0200154116129c957600080fd5b602435600b60043560e05260c052604060c02060c052602060c02055602435610140526004357fe57488a65fa53066d4c25bac90db47dda4e5de3025ac12bf76ff07211cf7f39e6020610140a2005b636cb56d19811415612d305760043560a01c15612a3457600080fd5b60243560a01c15612a4457600080fd5b6007543314612a5257600080fd5b600060243518612a6157600080fd5b60006001600b60043560e05260c052604060c02060c052602060c020015411612a8957600080fd5b6001600b60243560e05260c052604060c02060c052602060c020015415612aaf57600080fd5b610140600b60043560e05260c052604060c0208060c052602060c02054825260018160c052602060c0200154826020015260028160c052602060c0200154826040015260038160c052602060c0200154826060015260048160c052602060c0200154826080015260058160c052602060c02001548260a0015260068160c052602060c02001548260c0015260078160c052602060c02001548260e0015260088160c052602060c020015482610100015250506101405161016051610180516101a0516101c0516101e05161020051610220516102405160043561026052610260516006580161489d565b6102405261022052610200526101e0526101c0526101a052610180526101605261014052600050600f805461018051818183011015612bd757600080fd5b8082019050905081555060006006600b60043560e05260c052604060c02060c052602060c0200155600b60243560e05260c052604060c02060c052602060c0206101405181556101e05160018201556101805160028201556101a05160038201556101c05160048201556101e05160058201556102005160068201556000600782015560006008820155506004353b612c6f57600080fd5b60006000602463ce5494bb610260526024356102805261027c60006004355af1612c9857600080fd5b6024356004357f100b69bb6b504e1252e36b375233158edee64d071b399e2f81473a695fd1b02160006000a361026060006014818352015b6004356102605160148110612ce457600080fd5b600c60c052602060c02001541415612d1c576024356102605160148110612d0a57600080fd5b600c60c052602060c020015560006000f35b8151600101808352811415612cd0575b5050005b63a0e4af9a811415612d46573361014052612d77565b63bb994d48811415612d725760043560a01c15612d6257600080fd5b6020600461014037600050612d77565b612e29565b61014051610180526007546101a0526009546101c05260006101605261016061012060006003818352015b610120516020026101800151331415612dbe5760018352612dce565b8151600101808352811415612da2575b50505061016051612dde57600080fd5b60006002600b6101405160e05260c052604060c02060c052602060c020015418612e0757600080fd5b610140516101405161016052610160516006580161489d565b61014052600050005b63f76e4caa811415612fa55760043560a01c15612e4557600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b610120516020026101600151331415612e845760018352612e94565b8151600101808352811415612e68575b50505061014051612ea457600080fd5b60006001600b60043560e05260c052604060c02060c052602060c020015411612ecc57600080fd5b60006101405261018060006014818352015b61018051600c60c052602060c020015461016052610160511515612f0157612f43565b6004356101605118612f1257600080fd5b61014080516001818183011015612f2857600080fd5b808201905090508152505b8151600101808352811415612ede575b505060146101405110612f5557600080fd5b6004356013600c60c052602060c020015561014051600658016147ba565b610140526000506004357fa8727d412c6fa1e2497d6d6f275e2d9fe4d9318d5b793632e60ad9d38ee8f1fa60006000a2005b63b22439f58114156130cc5760043560a01c15612fc157600080fd5b600854610160526007546101805260006101405261014061012060006002818352015b6101205160200261016001513314156130005760018352613010565b8151600101808352811415612fe4575b5050506101405161302057600080fd5b61014060006014818352015b600435610140516014811061304057600080fd5b600c60c052602060c020015414156130b4576000610140516014811061306557600080fd5b600c60c052602060c020015561014051600658016147ba565b610140526000506004357f8e1ec3c16d6a67ea8effe2ac7adef9c2de0bc0dc47c49cdf18f6a8b0048085be60006000a260006000f35b815160010180835281141561302c575b505060006000fd5b63bf3759b58114156130e2573361014052613113565b63bdcf36bb81141561310e5760043560a01c156130fe57600080fd5b6020600461014037600050613113565b613141565b610140516101405161016052610160516006580161492c565b6101c052610140526101c05160005260206000f35b63112c1f9b811415613157573361014052613188565b63d76480138114156131835760043560a01c1561317357600080fd5b6020600461014037600050613188565b6131b6565b6101405161014051610160526101605160065801614a41565b6101c052610140526101c05160005260206000f35b63153c27c48114156132265760065801614266565b6101405261014051600e54111561321957600e546101405160065801614266565b6101605261014052610160518082101561320557600080fd5b8082039050905060005260206000f3613224565b600060005260206000f35b005b63d3406abd81141561323c57336101405261326d565b6333586b678114156132685760043560a01c1561325857600080fd5b602060046101403760005061326d565b61329b565b6101405161014051610160526101605160065801614c9c565b6101c052610140526101c05160005260206000f35b63a1d9bafc8114156137cc5760006001600b3360e05260c052604060c02060c052602060c0200154116132cd57600080fd5b6004356044358181830110156132e257600080fd5b8082019050905060206101c060246370a0823161014052336101605261015c6006545afa61330f57600080fd5b601f3d1161331c57600080fd5b6000506101c051101561332e57600080fd5b6000602435111561335a5733610140526024356101605261016051610140516006580161460c565b6000505b61014051336101605260043561018052610180516101605160065801614def565b6101e052610140526101e051610140526007600b3360e05260c052604060c02060c052602060c0200180546004358181830110156133b857600080fd5b80820190509050815550610140516101605133610180526101805160065801614a41565b6101e05261016052610140526101e05161016052610140516101605161018051336101a0526101a0516006580161492c565b610200526101805261016052610140526102005161018052604435610180518082111561343b578061343d565b815b905090506101a05260006101a05111156134c7576006600b3360e05260c052604060c02060c052602060c0200180546101a0518082101561347d57600080fd5b80820390509050815550601080546101a0518082101561349c57600080fd5b8082039050905081555061018080516101a051808210156134bc57600080fd5b808203905090508152505b600061016051111561352d576006600b3360e05260c052604060c02060c052602060c0200180546101605181818301101561350157600080fd5b80820190509050815550601080546101605181818301101561352257600080fd5b808201905090508155505b6004356101a05181818301101561354357600080fd5b808201905090506101c052610160516101c05110156135cd576101405161016051610180516101a0516101c0516006546101e0523361020052610160516101c0518082101561359157600080fd5b808203905090506102205261022051610200516101e05160065801613e10565b6101c0526101a052610180526101605261014052600050613651565b610160516101c0511115613651576101405161016051610180516101a0516101c0516006546101e052336102005230610220526101c051610160518082101561361557600080fd5b80820390509050610240526102405161022051610200516101e05160065801613faa565b6101c0526101a0526101805261016052610140526000505b426005600b3360e05260c052604060c02060c052602060c020015542601155600435610140518082101561368457600080fd5b808203905090506013556004356101e052602435610200526101a051610220526007600b3360e05260c052604060c02060c052602060c0200154610240526008600b3360e05260c052604060c02060c052602060c0200154610260526006600b3360e05260c052604060c02060c052602060c020015461028052610160516102a0526002600b3360e05260c052604060c02060c052602060c02001546102c052337f67f96d2854a335a4cadb49f84fd3ca6f990744ddb3feceeb4b349d2d53d32ad36101006101e0a26002600b3360e05260c052604060c02060c052602060c02001541515613774576001613778565b600d545b156137bd576020610240600463efbb5cb06101e0526101fc335afa61379c57600080fd5b601f3d116137a957600080fd5b6000506102405160005260206000f36137ca565b6101805160005260206000f35b005b6301681a62811415613802577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61014052613823565b636ea056a981141561381e576020602461014037600050613823565b613903565b60043560a01c1561383357600080fd5b600754331461384157600080fd5b6006546004351861385157600080fd5b61014051610160527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101605114156138c357602061020060246370a0823161018052306101a05261019c6004355afa6138aa57600080fd5b601f3d116138b757600080fd5b60005061020051610160525b6101405161016051600435610180526007546101a052610160516101c0526101c0516101a0516101805160065801613e10565b6101605261014052600050005b6306fdde038114156139a85760008060c052602060c020610180602082540161012060006003818352015b8261012051602002111561394157613963565b61012051850154610120516020028501525b815160010180835281141561392e575b50505050505061018051806101a001818260206001820306601f82010390500336823750506020610160526040610180510160206001820306601f8201039050610160f35b6395d89b41811415613a4d5760018060c052602060c020610180602082540161012060006002818352015b826101205160200211156139e657613a08565b61012051850154610120516020028501525b81516001018083528114156139d3575b50505050505061018051806101a001818260206001820306601f82010390500336823750506020610160526040610180510160206001820306601f8201039050610160f35b63313ce567811415613a655760025460005260206000f35b6370a08231811415613a9b5760043560a01c15613a8157600080fd5b600360043560e05260c052604060c0205460005260206000f35b63dd62ed3e811415613aef5760043560a01c15613ab757600080fd5b60243560a01c15613ac757600080fd5b600460043560e05260c052604060c02060243560e05260c052604060c0205460005260206000f35b6318160ddd811415613b075760055460005260206000f35b63fc0c546a811415613b1f5760065460005260206000f35b635aa6e675811415613b375760075460005260206000f35b6388a8d602811415613b4f5760085460005260206000f35b63452a9320811415613b675760095460005260206000f35b6339ebf823811415613c815760043560a01c15613b8357600080fd5b600b60043560e05260c052604060c0206101408080808460c052602060c0205481525050602081019050808060018560c052602060c020015481525050602081019050808060028560c052602060c020015481525050602081019050808060038560c052602060c020015481525050602081019050808060048560c052602060c020015481525050602081019050808060058560c052602060c020015481525050602081019050808060068560c052602060c020015481525050602081019050808060078560c052602060c020015481525050602081019050808060088560c052602060c0200154815250506101209050905060c05260c051610140f35b63c822adda811415613cb25760043560148110613c9d57600080fd5b600c60c052602060c020015460005260206000f35b633403c2fc811415613cca57600d5460005260206000f35b63ecf70858811415613ce257600e5460005260206000f35b63cea55f57811415613cfa57600f5460005260206000f35b63fc7b9c18811415613d125760105460005260206000f35b63c3535b52811415613d2a5760115460005260206000f35b633629c8de811415613d425760125460005260206000f35b6344b81396811415613d5a5760135460005260206000f35b6342232716811415613d725760145460005260206000f35b639ec5a894811415613d8a5760155460005260206000f35b63a6f7f5d6811415613da25760165460005260206000f35b6387788782811415613dba5760175460005260206000f35b637ecebe00811415613df05760043560a01c15613dd657600080fd5b601860043560e05260c052604060c0205460005260206000f35b633644e515811415613e085760195460005260206000f35b505b60006000fd5b6101a05261014052610160526101805260006004610220527fa9059cbb000000000000000000000000000000000000000000000000000000006102405261022060048060208461028001018260208501600060045af15050805182019150506101605160208261028001015260208101905061018051602082610280010152602081019050806102805261028090508051602001806103208284600060045af1613eb957600080fd5b505060206103e0610320516103406000610140515af1613ed857600080fd5b60203d80821115613ee95780613eeb565b815b905090506103c0526103c08051602001806101c08284600060045af1613f1057600080fd5b505060006101c0511115613fa4576101c0806020015160008251806020901315613f3957600080fd5b8091901215613f4757600080fd5b806020036101000a820490509050905015151515613fa4576308c379a0610220526020610240526010610260527f5472616e73666572206661696c656421000000000000000000000000000000006102805261026050606461023cfd5b6101a051565b6101c0526101405261016052610180526101a05260006004610240527f23b872dd00000000000000000000000000000000000000000000000000000000610260526102406004806020846102a001018260208501600060045af1505080518201915050610160516020826102a0010152602081019050610180516020826102a00101526020810190506101a0516020826102a0010152602081019050806102a0526102a090508051602001806103608284600060045af161406a57600080fd5b50506020610440610360516103806000610140515af161408957600080fd5b60203d8082111561409a578061409c565b815b90509050610420526104208051602001806101e08284600060045af16140c157600080fd5b505060006101e0511115614155576101e08060200151600082518060209013156140ea57600080fd5b80919012156140f857600080fd5b806020036101000a820490509050905015151515614155576308c379a0610240526020610260526010610280527f5472616e73666572206661696c656421000000000000000000000000000000006102a05261028050606461025cfd5b6101c051565b6101a052610140526101605261018052306101e05260006102005260006101c0526101c061012060006002818352015b610120516020026101e001516101605114156141aa57600183526141ba565b815160010180835281141561418b575b5050506101c051156141cb57600080fd5b60036101405160e05260c052604060c020805461018051808210156141ef57600080fd5b8082039050905081555060036101605160e05260c052604060c02080546101805181818301101561421f57600080fd5b80820190509050815550610180516101c05261016051610140517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206101c0a36101a051565b6101405260206101e060246370a0823161016052306101805261017c6006545afa61429057600080fd5b601f3d1161429d57600080fd5b6000506101e0516010548181830110156142b657600080fd5b8082019050905060005260005161014051565b61018052610140526101605260006101a0526005546101c05260006101c051111561436457610160516101c051808202821582848304141761430a57600080fd5b809050905090506101405161016051610180516101a0516101c05160065801614266565b6101e0526101c0526101a0526101805261016052610140526101e051808061435557600080fd5b8204905090506101a05261436d565b610160516101a0525b60006101a0511861437d57600080fd5b6101c0516101a05181818301101561439457600080fd5b8082019050905060055560036101405160e05260c052604060c02080546101a0518181830110156143c457600080fd5b808201905090508155506101a0516101e0526101405160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206101e0a36101a05160005260005161018051565b61016052610140526005541515614434576101405160005260005161016051565b426011548082101561444557600080fd5b80820390509050601454808202821582848304141761446357600080fd5b80905090509050610180526101405161016051610180516101a05160065801614266565b6101c0526101a0526101805261016052610140526101c0516101a052670de0b6b3a764000061018051101561451c576101a080516013546101805160135480820282158284830414176144d957600080fd5b80905090509050670de0b6b3a764000080820490509050808210156144fd57600080fd5b808203905090508082101561451157600080fd5b808203905090508152505b610140516101a051808202821582848304141761453857600080fd5b80905090509050600554808061454d57600080fd5b82049050905060005260005161016051565b61016052610140526000610140516101605160065801614266565b6101805261016052610140526101805111156145fc576101405160055480820282158284830414176145ab57600080fd5b8090509050905061014051610160516101805160065801614266565b6101a0526101805261016052610140526101a05180806145e657600080fd5b820490509050600052600051610160515661460a565b600060005260005161016051565b005b6101805261014052610160526006600b6101405160e05260c052604060c02060c052602060c02001546101a052610160516101a051101561464c57600080fd5b60006101c0526000600f5418156146c95761016051600f54808202821582848304141761467857600080fd5b80905090509050601054808061468d57600080fd5b8204905090506002600b6101405160e05260c052604060c02060c052602060c0200154808211156146be57806146c0565b815b905090506101c0525b6008600b6101405160e05260c052604060c02060c052602060c020018054610160518181830110156146fa57600080fd5b808201905090508155506101a051610160518082101561471957600080fd5b808203905090506006600b6101405160e05260c052604060c02060c052602060c020015560108054610160518082101561475257600080fd5b808203905090508155506002600b6101405160e05260c052604060c02060c052602060c0200180546101c0518082101561478b57600080fd5b80820390509050815550600f80546101c051808210156147aa57600080fd5b8082039050905081555061018051565b6101405260006101605261018060006014818352015b61018051601481106147e157600080fd5b600c60c052602060c02001546101a0526101a0511515614820576101608051600181818301101561481157600080fd5b80820190509050815250614885565b6000610160511115614885576101a05161018051610160518082101561484557600080fd5b808203905090506014811061485957600080fd5b600c60c052602060c02001556000610180516014811061487857600080fd5b600c60c052602060c02001555b81516001018083528114156147d0575b505061014051565b6101605261014052600f80546002600b6101405160e05260c052604060c02060c052602060c0200154808210156148d357600080fd5b8082039050905081555060006002600b6101405160e05260c052604060c02060c052602060c0200155610140517f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a60006000a261016051565b6101605261014052600f541515614966576006600b6101405160e05260c052604060c02060c052602060c020015460005260005161016051565b6002600b6101405160e05260c052604060c02060c052602060c0200154601054808202821582848304141761499a57600080fd5b80905090509050600f5480806149af57600080fd5b820490509050610180526006600b6101405160e05260c052604060c02060c052602060c02001546101a052600d54156149f6576101a0516000526000516101605156614a3f565b610180516101a051111515614a175760006000526000516101605156614a3f565b6101a0516101805180821015614a2c57600080fd5b8082039050905060005260005161016051565b005b6101605261014052600d5415614a5f57600060005260005161016051565b61014051610160516101805160065801614266565b6101a0526101805261016052610140526101a05161018052600f54610180518082028215828483041417614aa757600080fd5b80905090509050612710808204905090506101a0526010546101c0526002600b6101405160e05260c052604060c02060c052602060c0200154610180518082028215828483041417614af857600080fd5b80905090509050612710808204905090506101e0526006600b6101405160e05260c052604060c02060c052602060c0200154610200526003600b6101405160e05260c052604060c02060c052602060c0200154610220526004600b6101405160e05260c052604060c02060c052602060c020015461024052610200516101e051111515614b86576001614b91565b6101c0516101a05111155b15614ba457600060005260005161016051565b6101e0516102005180821015614bb957600080fd5b8082039050905061026052610260516101a0516101c05180821015614bdd57600080fd5b8082039050905080821115614bf25780614bf4565b815b905090506102605261026051602061030060246370a0823161028052306102a05261029c6006545afa614c2657600080fd5b601f3d11614c3357600080fd5b6000506103005180821115614c485780614c4a565b815b905090506102605261022051610260511015614c725760006000526000516101605156614c9a565b610260516102405180821115614c885780614c8a565b815b9050905060005260005161016051565b005b61016052610140526005600b6101405160e05260c052604060c02060c052602060c020015461018052426101805180821015614cd757600080fd5b808203905090506101a052610180516001600b6101405160e05260c052604060c02060c052602060c020015480821015614d1057600080fd5b808203905090506101c05260006101a0511115614d765760006101c0511115614d6e5760206102c060046322f3e2d46102605261027c610140515afa614d5557600080fd5b601f3d11614d6257600080fd5b6000506102c051614d71565b60005b614d79565b60005b15614ddf576007600b6101405160e05260c052604060c02060c052602060c02001546101a0518082028215828483041417614db357600080fd5b809050905090506101c0518080614dc957600080fd5b8204905090506000526000516101605156614ded565b600060005260005161016051565b005b610180526101405261016052426005600b6101405160e05260c052604060c02060c052602060c020015480821015614e2657600080fd5b808203905090506101a05260006101a05118614e4157600080fd5b6006600b6101405160e05260c052604060c02060c052602060c020015460206102406004638e6350e26101e0526101fc610140515afa614e8057600080fd5b601f3d11614e8d57600080fd5b6000506102405180821015614ea157600080fd5b808203905090506101a0518082028215828483041417614ec057600080fd5b809050905090506016548082028215828483041417614ede57600080fd5b80905090509050612710808204905090506301e18558808204905090506101c0526040366101e0376000610160511115614f8a5761016051600b6101405160e05260c052604060c02060c052602060c020548082028215828483041417614f4457600080fd5b80905090509050612710808204905090506101e052610160516017548082028215828483041417614f7457600080fd5b8090509050905061271080820490509050610200525b610200516101e051818183011015614fa157600080fd5b808201905090506101c051818183011015614fbb57600080fd5b808201905090506102205261016051610220511115615015576101605161022052610160516102005180821015614ff157600080fd5b808203905090506101e0518082101561500957600080fd5b808203905090506101c0525b60006102205111156151f0576101405161016051610180516101a0516101c0516101e051610200516102205161024051306102605261022051610280526102805161026051600658016142c9565b6102e0526102405261022052610200526101e0526101c0526101a0526101805261016052610140526102e0516102405260006101e0511115615159576101e0516102405180820282158284830414176150bb57600080fd5b809050905090506102205180806150d157600080fd5b820490509050610260526101405161016051610180516101a0516101c0516101e051610200516102205161024051610260513061028052610140516102a052610260516102c0526102c0516102a051610280516006580161415b565b610260526102405261022052610200526101e0526101c0526101a0526101805261016052610140526000505b600060033060e05260c052604060c0205411156151f0576101405161016051610180516101a0516101c0516101e05161020051610220516102405130610260526015546102805260033060e05260c052604060c020546102a0526102a05161028051610260516006580161415b565b6102405261022052610200526101e0526101c0526101a0526101805261016052610140526000505b6102205160005260005161018051565b61000461520403610004600039610004615204036000f3"

func TestDeploy(t *testing.T) {
	skipBelowVersion(t, 3)
	ctx := context.Background()
	backend, _, client, auth, _, _, _, _, cancel := setupFeeChain(t, ctx)
	defer cancel()
	estimatedGas, err := client.EstimateGas(ctx, ethereum.CallMsg{
		From: auth.From,
		Data: hexutil.MustDecode(conData),
	})
	test.FailIfError(t, err)
	t.Log("estimated", estimatedGas)
	nonce, err := client.PendingNonceAt(ctx, auth.From)
	test.FailIfError(t, err)
	tx := types.NewTx(&types.LegacyTx{
		Nonce:    nonce,
		GasPrice: big.NewInt(1 << 60),
		Gas:      estimatedGas * 2,
		Value:    big.NewInt(0),
		Data:     hexutil.MustDecode(conData),
	})
	tx, err = auth.Signer(auth.From, tx)
	err = client.SendTransaction(ctx, tx)
	test.FailIfError(t, err)
	arbRes, _, _, err := backend.db.GetRequest(common.NewHashFromEth(tx.Hash()))
	test.FailIfError(t, err)
	t.Log(arbRes)
}
